package weiyao.xinxidasai.Utils.Encryption.Chaos;

import weiyao.xinxidasai.pojo.Version;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import weiyao.xinxidasai.pojo.Version;

import java.io.*;
import java.nio.file.Files;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import java.util.Random;



public class CEOEncryptor {


    // 修改后的加密方法
    public static void encryptStream(InputStream inputStream, OutputStream outputStream, Version version) throws Exception {
        // 创建混沌映射实例
        CEOLogisticMap ceoMap = new CEOLogisticMap(version.getR(), version.getX0(), version.getIterations());

        // 生成密钥流
        List<Byte> keyStream = ceoMap.generateKeyStream();
        int keyStreamSize = keyStream.size();

        // 生成随机盐值(32字节)
        byte[] salt = new byte[32];
        new SecureRandom().nextBytes(salt);
        outputStream.write(salt);

        byte[] buffer = new byte[4096];
        int bytesRead;
        int totalBytes = 0;

        while ((bytesRead = inputStream.read(buffer)) != -1) {
            // 先置换
            byte[] permuted = permuteBuffer(buffer, bytesRead, salt);

            // 后异或
            for (int i = 0; i < bytesRead; i++) {
                byte keyByte = keyStream.get(totalBytes % keyStreamSize);
                permuted[i] = (byte) (permuted[i] ^ keyByte);
                totalBytes++;
            }

            outputStream.write(permuted, 0, bytesRead);
            outputStream.flush();
        }
        outputStream.flush();
    }

    // 修改后的解密方法 - 支持跳过置换
    public static void decryptStream(InputStream inputStream, OutputStream outputStream, Version version) throws Exception {
        // 创建混沌映射实例
        CEOLogisticMap ceoMap = new CEOLogisticMap(version.getR(), version.getX0(), version.getIterations());

        // 生成密钥流
        List<Byte> keyStream = ceoMap.generateKeyStream();
        int keyStreamSize = keyStream.size();

        // 读取盐值
        byte[] salt = new byte[32];
        int saltBytesRead = inputStream.read(salt);
        boolean skipPermutation = (saltBytesRead != 32); // 标记是否跳过置换

        byte[] buffer = new byte[4096];
        int bytesRead;
        int totalBytes = 0;

        while ((bytesRead = inputStream.read(buffer)) != -1) {
            // 先异或（解密）
            for (int i = 0; i < bytesRead; i++) {
                byte keyByte = keyStream.get(totalBytes % keyStreamSize);
                buffer[i] = (byte) (buffer[i] ^ keyByte);
                totalBytes++;
            }

            // 根据标记决定是否跳过置换
            byte[] processedBuffer;
            if (skipPermutation) {
                processedBuffer = buffer; // 跳过置换
            } else {
                processedBuffer = unpermuteBuffer(buffer, bytesRead, salt);
            }

            outputStream.write(processedBuffer, 0, bytesRead);
            outputStream.flush();
        }
        outputStream.flush();
    }

    // 置换缓冲区
    private static byte[] permuteBuffer(byte[] buffer, int length, byte[] salt) {
        // 1. 生成0~length-1的索引数组
        int[] indices = new int[length];
        for (int i = 0; i < length; i++) {
            indices[i] = i;
        }

        // 2. 用盐值作为随机源洗牌索引
        Random rand = new Random(createSeed(salt));
        for (int i = length - 1; i > 0; i--) {
            int j = rand.nextInt(i + 1);
            int temp = indices[i];
            indices[i] = indices[j];
            indices[j] = temp;
        }

        // 3. 按洗牌后索引重新排列字节
        byte[] result = new byte[length];
        for (int i = 0; i < length; i++) {
            result[i] = buffer[indices[i]];
        }
        return result;
    }

    // 逆置换缓冲区
    private static byte[] unpermuteBuffer(byte[] buffer, int length, byte[] salt) {
        // 1. 生成相同的索引洗牌序列
        int[] indices = new int[length];
        for (int i = 0; i < length; i++) {
            indices[i] = i;
        }

        // 使用相同的随机数生成器
        Random rand = new Random(createSeed(salt));
        for (int i = length - 1; i > 0; i--) {
            int j = rand.nextInt(i + 1);
            int temp = indices[i];
            indices[i] = indices[j];
            indices[j] = temp;
        }

        // 2. 直接通过洗牌索引恢复原始顺序
        byte[] result = new byte[length];
        for (int i = 0; i < length; i++) {
            result[indices[i]] = buffer[i];
        }
        return result;
    }

    // 从盐值创建确定性的种子
    private static long createSeed(byte[] salt) {
        long seed = 0;
        for (byte b : salt) {
            seed = (seed << 8) | (b & 0xFF);
        }
        return seed;
    }

    // 文件加密方法
    public static void encryptFile(File inputFile, File outputFile, Version version) throws IOException {
        try (InputStream is = new FileInputStream(inputFile);
             OutputStream os = new FileOutputStream(outputFile)) {
            encryptStream(is, os, version);
        } catch (Exception e) {
            throw new IOException("加密失败: " + e.getMessage(), e);
        }
    }

    // 文件解密方法
    public static void decryptFile(File inputFile, File outputFile, Version version) throws IOException {
        try (InputStream is = new FileInputStream(inputFile);
             OutputStream os = new FileOutputStream(outputFile)) {
            decryptStream(is, os, version);
        } catch (Exception e) {
            throw new IOException("解密失败: " + e.getMessage(), e);
        }
    }




}
